fix(web): DOG bugbash burn — 9 fixes across marketing/pricing/checkout/docs/for-agents#149
Merged
Merged
Conversation
…t/docs/for-agents Closes 9 personal-dogfood + BUG-PAYMENT findings discovered in the 2026-05-29 QA sweep. Each fix carries a code-comment with the DOG-/BUG- ID and the behavior contract for the regression guard. Funnel impact (Team self-serve + lost-context redirect): - DOG-1, DOG-10, BUG-P003: Team CTA mailto:support@instanode.dev flipped to /app/checkout?plan=team&frequency=monthly|yearly on both MarketingPage and PricingPage. Self-serve Team is live as of api#168 + dashboard #106; the prior mailto contradicted the H2 'Self-serve at every tier' on the same page and leaked mid-funnel conversions on the $199/mo AOV path. - DOG-9, BUG-P013: AuthGate now redirects unauthenticated /app/* visits to /login?next=<encoded path> on the URL (not just React Router state). State doesn't survive OAuth or magic-link callbacks — net effect was every logged-out 'Start hobby' click landed back on /app/dashboard with all plan + frequency context lost. New App.authgate.test.tsx pins the contract. Copy honesty (DOG-3 + DOG-11 + DOG-47/48): - DOG-11: 'Self-serve at every tier' H2 → 'Self-serve sign-up at every tier'. The signup direction is honest; cancellation/downgrade stays support-only per the intentional policy (memory: project_no_self_serve_cancel_downgrade.md). - DOG-3, BUG-P001: hobby_plus + growth tiers were FAQ-only despite the 'every tier' promise. Added 'Between the headline tiers' inline section on PricingPage with per-tier markers + cross-link from the FAQ entry. The comparison table stays 4-column (cleaner first-time funnel); the inline callout makes the intermediate tiers discoverable. - DOG-47/48: 'Try the curl' CTAs renamed to 'See the curl' (landing + pricing). Both anchors land on static screenshots, not REPLs — the previous label false-promised interactivity. Building a real playground is separately scoped. DocsPage (DOG-33 + DOG-34): - DOG-33: search input now filters the MAIN article column too, not just the sidebar TOC. Previously typing 'razorpay' left every <section> visible in the body. Empty-query renders all sections; no-match renders the empty state. - DOG-34: Edit-on-GitHub link moved OUT of the <h2> into a .docs-section-header sibling. Screen readers used to announce section titles as 'QuickstartEdit on GitHub ↗'; the new header preserves the visual side-by-side layout while keeping the heading clean for AT and the document outline. For-agents page (DOG-39): - DOG-39: added 'instanode CLI' integration card with the curl|sh one-liner. cli#18 + .goreleaser.yml release notes documented the install path but the page only listed MCP runtimes; the cli persona was invisible. DOG-38 was already fixed (aria-label='Copy …' on each copy button). Tests added (1081 passing, 0 failing — was 1075 before): - src/App.authgate.test.tsx (NEW): pins ?next= preservation contract, including the bare-/app no-query case and the token-present passthrough. - PricingPage.test.tsx: Team CTA points at /app/checkout?plan=team (monthly default + ?frequency=yearly URL-param variant), 'Between the headline tiers' section + per-tier markers. - DocsPage.test.tsx: search filters main column on no-match; empty query renders everything; Edit link is a sibling of h2, not a child. Coverage block: Symptom: marketing CTAs / a11y / SPA redirect drops query Enumeration: rg 'Team plan inquiry', 'Try the curl', 'Self-serve at every tier' Sites found: 8 distinct surfaces Sites touched: 8 (all enumerated above) Coverage test: new tests in App.authgate / PricingPage / DocsPage Live verified: awaiting deploy (curl /pricing | grep '/app/checkout?plan=team') Rule 22 multi-surface notes: - llms.txt was updated by the prebuild fetch-content step (unrelated to this PR — content repo had drift). - Dashboard checkout copy (upgradeCopy.ts) does not need updates — these changes are marketing-side only; CheckoutPage itself already handles the ?plan=team case via the ALLOWED_PLANS list. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
size-limit report 📦
|
Patch-coverage gate flagged 4 lines uncovered: - src/App.tsx:208,211-212 — AuthGate body. Previous test imported a parallel AuthGate copy in the test file rather than the real export, so the gate's diff-cover saw 0% on the new lines. Fix: export AuthGate from App.tsx and import it directly. Same 3 cases, now hit the real implementation. - src/pages/DocsPage.tsx:246 — the filter() predicate at the section-render loop. Added an explicit matching-query test that exercises both branches (visibleIds === null when query is empty, visibleIds.has(s.id) when there is a query). Local gate now 1082 passed / 0 failed (was 1081 — added 1 new test). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…CI hits all patch lines
Previous shape used an inline {SECTIONS.filter(predicate).map(render)} at L246.
The lcov v8 reporter only emits DA records for function bodies, not for the
JSX expression line itself — so the filter callback function on L246 was the
only thing diff-cover could track. In CI the docs corpus is empty (the
.content/docs/ glob has no prebuilt files because the coverage job skips
the prebuild step), so the filter callback was never invoked → diff-cover
reported L246 uncovered (80%).
Refactor: move the filter into a useMemo'd visibleSections array. The main
column now does {visibleSections.map(s => <section>)}; line 246 becomes a
pure JSX iteration over a precomputed list, no inline arrow. The useMemo
body itself runs unconditionally on mount, so every patch line is hit even
when SECTIONS is empty.
Also extracts noMatches as an explicit boolean so the empty-state branch is
independently testable. Same behavior — just untangled for the coverage gate.
Drive-by: add coverage/ to .gitignore (accidentally tracked locally; CI
generates it under the gitignored output path).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Earlier refactor moved the filter into a useMemo but left the section JSX
as an inline {visibleSections.map((s) => <section>...)} — the arrow
callback is still a tracked function and never runs in coverage CI because
.content/docs/ is empty.
Solution: extract renderDocSection as an exported top-level function and
test it directly with a synthetic fixture {id, title, body}. The main column
becomes {renderedSections} — a precomputed React-node array, no inline
arrow at the render site. Coverage is now corpus-independent.
Local gate: 1083 passing / 0 failing.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes 9 personal-dogfood + BUG-PAYMENT findings from the 2026-05-29 QA sweep. Each fix carries a code-comment with the DOG-/BUG- ID and the behavior contract for the regression guard.
Funnel impact
Copy honesty
DocsPage
into a .docs-section-header sibling. Screen readers used to announce section titles as 'QuickstartEdit on GitHub ↗'.
For-agents page
Tests
src/App.authgate.test.tsx(3 cases): pins ?next= preservation, bare-/app no-query case, token-present passthrough.Coverage block (CLAUDE.md rule 17)
Multi-surface notes (rule 22)
🤖 Generated with Claude Code